﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Web;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Text.RegularExpressions;

namespace DetectLanguage02
{
    public class DetectLanguage
    {
        #region Vars
        private string API_KEY;

        private long _Bytes;
        private long _BytesLimit;
        private long _Requests;
        private long _RequestsLimit;
        #endregion

        public DetectLanguage(string ApiKey)
        {
            API_KEY = ApiKey;
            UpdateUserStatus();
        }

        public LanguagePool Detect(string Query)
        {
            if (IsLimitReach)
                return null;

            Query = Query.Replace(" ", "+");

            try
            {
                string Data = GetStringFromUrl(string.Format("http://ws.detectlanguage.com/0.2/detect?q={0}&key={1}", Query, API_KEY));
                JsonTextReader reader = new JsonTextReader(new StringReader(Data));
                JObject jobj = (JObject)new JsonSerializer().Deserialize(reader);

                LanguagePool pool = new LanguagePool();
                JToken tk1 = jobj["data"]["detections"];
                foreach (var v in tk1)
                    pool.Add(new DetectLanguageResult(v));

                UpdateUserStatus();
                return pool;
            }
            catch { }

            return null;
        }
        public LanguagePool SmartDetect(string Query)
        {
            int _byteRacio = (int)((4 * _BytesLimit) / _RequestsLimit);
            if (_byteRacio < 100)
                _byteRacio = 100;

            Query = FilterString(Query);
            if (Query.Length > _byteRacio)
                Query = Query.Substring(0, _byteRacio);

            return Detect(Query);
        }

        public void UpdateUserStatus()
        {
            if (API_KEY == "demo")
                IsLimitReach = false;
            else
            {
                string Data = GetStringFromUrl(string.Format("http://ws.detectlanguage.com/0.2/user/status?key={0}", API_KEY));
                JsonTextReader reader = new JsonTextReader(new StringReader(Data));
                JObject jobj = (JObject)new JsonSerializer().Deserialize(reader);

                _Bytes = Convert.ToInt64(jobj["bytes"].ToString());
                _BytesLimit = Convert.ToInt64(jobj["daily_bytes_limit"].ToString());
                _Requests = Convert.ToInt64(jobj["requests"].ToString());
                _RequestsLimit = Convert.ToInt64(jobj["daily_requests_limit"].ToString());

                if (_Requests == _RequestsLimit)
                    IsLimitReach = true;
                else
                    IsLimitReach = false;
            }

        }
        public bool IsLimitReach
        { get; set; }

        private string GetStringFromUrl(string Url)
        {
            WebClient c = new WebClient();
            c.Headers.Add("Accept: application/json");
            c.Encoding = Encoding.UTF8;

            return c.DownloadString(Url);
        }
        private string FilterString(string Query)
        {
            string compare = "";
            foreach (var v in Query.Where(e => char.IsDigit(e) || Regex.IsMatch(e.ToString(), @"^[\/_?!.:,;+]+$")))
            {
                if (compare.IndexOf(v) == -1)
                    compare += v;
            }

            foreach (var v in compare)
                Query = Query.Replace(v.ToString(), "");

            Query = Query.Replace('\n', ' ');
            Query = Query.Replace('\r', ' ');
            Query = Query.Replace("  ", " ");
            Query = Query.Replace(" ", "+");
            Query = Query.Replace("++", "+");

            return Query;
        }
    }

    public class DetectLanguageResult
    {
        public DetectLanguageResult(JToken Result)
        {
            Lang = Result["language"].ToString();
            IsReliable = Convert.ToBoolean(Result["isReliable"].ToString());
            Confidence = Convert.ToDouble(Result["confidence"].ToString()) * 100;
        }

        public string Lang
        { get; set; }
        public bool IsReliable
        { get; set; }
        public double Confidence
        { get; set; }
    }
    public class LanguagePool
    {
        private List<DetectLanguageResult> _pool;

        public LanguagePool()
        {
            _pool = new List<DetectLanguageResult>();
        }
        public void Add(DetectLanguageResult Result)
        {
            _pool.Add(Result);
            _pool = new List<DetectLanguageResult>(_pool.OrderByDescending(e => e.Confidence));
        }
        public int Count
        { get { return _pool.Count; } }
        public int UnknownCount
        { get { return _pool.Count(e => e.Lang == "xxx"); } }

        public List<DetectLanguageResult> Results
        { get { return _pool; } }
        public DetectLanguageResult GetReliableResult()
        {
            if (_pool.Count(e => e.IsReliable) > 0)
                return _pool.First(e => e.IsReliable);

            return null;
        }
        public DetectLanguageResult GetBestResult(double MinScore = 30)
        {
            DetectLanguageResult res = GetReliableResult();
            if (res != null)
                return res;

            if (_pool.Count(e => e.Confidence >= MinScore) > 0)
                return _pool.First(e => e.Confidence >= MinScore);

            return null;
        }
    }
}
